package com.caigou.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.caigou.bean.cms.entity.*;
import com.caigou.bean.cms.param.*;
import com.caigou.bean.exam.entity.UserInfo;
import com.caigou.bean.exam.entity.Users;
import com.caigou.component.OSSComponent;
import com.caigou.component.RedisComponent;
import com.caigou.component.RedisObjectComponent;
import com.caigou.component.SnowflakeComponent;
import com.caigou.constant.NewsConstant;
import com.caigou.mapper.cms.*;
import com.caigou.mapper.exam.UserInfoMapper;
import com.caigou.mapper.exam.UsersMapper;
import com.caigou.service.ContributeService;
import com.caigou.util.Result;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.Bean;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Slf4j
@Service("contributeService")
public class ContributeServiceImpl implements ContributeService {

    @Resource
    private ContributeMapper contributeMapper;
    @Resource
    private ContributeAttachmentMapper contributeAttachmentMapper;
    @Resource
    private ContributeChannelMapper contributeChannelMapper;
    @Resource
    private ContributeTypeMapper contributeTypeMapper;
    @Resource
    private ContributePublishTypeMapper contributePublishTypeMapper;

    @Resource
    private AttachmentConfigMapper attachmentConfigMapper;

    @Resource
    private UsersMapper usersMapper;
    @Resource
    private UserInfoMapper userInfoMapper;
    @Resource
    private UserBaseInfoMapper userBaseInfoMapper;

    @Resource
    private SnowflakeComponent snowflakeComponent;// 雪花UUID组件
    @Resource
    private OSSComponent ossComponent;

    @Resource
    private RedisComponent redisComponent;
    @Resource
    private RedisObjectComponent redisObjectComponent;

    public Contribute selectContributeByPrimaryKey(int id) {
        return contributeMapper.selectByPrimaryKey(id);
    }

    public Result saveContribute(Contribute contribute, MultipartFile[] files) {
        AttachmentConfig attachmentConfig = attachmentConfigMapper.selectByType(1);
        if(attachmentConfig!=null) {
            int maxCount = attachmentConfig.getMaxCount();
            if (files.length > maxCount) {
                return Result.error("最多只能上传" + maxCount + "个附件", "最多只能上传" + maxCount + "个附件");
            }
            int maxSize = attachmentConfig.getMaxSize();
            for(MultipartFile multipartFile:files){
                if(multipartFile.getSize()>maxSize*1024*1024){
                    return Result.error("文件最大" + maxSize + "MB，请重新上传", "文件最大" + maxSize + "MB，请重新上传");
                }
            }
        }
        int result = contributeMapper.insertSelective(contribute);
        if (result > 0) {
            //处理投稿上传
//            String contributeFolder = NewsConstant.CONTRIBUTE_ROOT;
//            log.info("上传投稿到oss的目录={}", contributeFolder);
            //多文件上传
            int failCount = 0;//文件上传失败数量
            int successCount = 0;//文件上传成功数量
            ContributeService proxy = (ContributeService) AopContext.currentProxy();
            StringBuffer sb = new StringBuffer("第");
            int uploadResult = 0;
            for (int i = 0; i < files.length; i++) {
                MultipartFile multipartFile = files[i];
                log.info("before 上传投稿pictureInfo={}, i={}", multipartFile.getOriginalFilename(), i);
                try {
                    uploadResult = proxy.uploadContribute(multipartFile, i, contribute.getId());
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
                if (uploadResult > 0) {
                    successCount++;
                } else {
                    failCount++;
                    sb.append((i + 1)).append("、");
                }
            }
            if(failCount==0){//全部成功
                return Result.success("投稿成功");
            }else if(successCount==0){//全部失败
                return Result.error(failCount+"个投稿上传全部失败", failCount+"个投稿上传全部失败");
            }else{//部分成功、部分失败
                sb.deleteCharAt(sb.length() - 1);//删除最后一个字符
                return Result.custom(400,failCount+"个（"+sb.toString()+")投稿上传失败,"+successCount+"个投稿上传成功",failCount+"个（"+sb.toString()+")投稿上传失败,"+successCount+"个投稿上传成功");
            }
        } else {
            return Result.error("投稿失败", "投稿失败");
        }
    }

    public Contribute selectContributeDetailByPrimaryKey(int id){
        return contributeMapper.selectDetailByPrimaryKey(id);
    }

    /**
     * 处理单个投稿文件上传
     *
     * @param multipartFile
     * @param i
     * @param
     * @param
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Throwable.class)
    public int uploadContribute(MultipartFile multipartFile, int i, int contributeId) {
        try {
            String fileName = multipartFile.getOriginalFilename();
            log.info("第{}个文稿，fileName={}", i, fileName);
            String fileExtension = "";
            int idx = fileName.lastIndexOf(".");
            if (idx > 0) {
                fileExtension = fileName.substring(idx);
            } else {
                log.error("上传文稿错误，没有扩展名, fileName={}", fileName);
                return 0;
            }
            //文件重命名
            long snowflakeId = snowflakeComponent.getInstance().nextId();
            String newFileName = snowflakeId + fileExtension;
            String strSnowflakeId = String.valueOf(snowflakeId);
            int length = strSnowflakeId.length();
            String contributeFolder = NewsConstant.CONTRIBUTE_ROOT + "/" + strSnowflakeId.substring(length - 4, length - 2) + "/" + strSnowflakeId.substring(length - 2, length) + "/";

            //上传投稿文件
            InputStream originInputStream = multipartFile.getInputStream();
            String fileUrl = ossComponent.uploadToOSS(originInputStream, fileName, newFileName, contributeFolder);

            ContributeAttachment contributeAttachment = new ContributeAttachment();
            contributeAttachment.setContributeId(contributeId);
            contributeAttachment.setFileName(multipartFile.getOriginalFilename());
            contributeAttachment.setFileSize(multipartFile.getSize());
            contributeAttachment.setFileType(fileExtension);
            contributeAttachment.setFileUrl(fileUrl);
            Date currentTime = new Date(System.currentTimeMillis());
            contributeAttachment.setCreateTime(currentTime);
            contributeAttachment.setUpdateTime(currentTime);
            return contributeAttachmentMapper.insertSelective(contributeAttachment);
        } catch (IOException ioe) {
            log.error(ioe.getMessage(), ioe);
            throw new RuntimeException(ioe);
        }
    }


    public ContributeChannel selectContributeChannelByPrimaryKey(int id){
        return contributeChannelMapper.selectByPrimaryKey(id);
    }

    public Result saveContributeChannel(ContributeChannelParam param){
        int count= contributeChannelMapper.getContributeChannelCount();
        if(count>=16){
            return Result.error("投稿频道数量已经超过15个，不能再增加", "投稿频道数量已经超过15个，不能再增加");
        }
        ContributeChannel contributeChannel = new ContributeChannel();
        BeanUtil.copyProperties(param, contributeChannel);
        Date currentTime = new Date(System.currentTimeMillis());
        contributeChannel.setCreateTime(currentTime);
        contributeChannel.setUpdateTime(currentTime);
        int result = 0;
        try{
            result = saveContributeChannel(contributeChannel);
        }catch(DataAccessException e){
            log.error(e.getMessage(), e);
            return Result.error("投稿频道名称功能重复", "投稿频道名称功能重复");
        }
        if(result>0){
            return Result.success("新增投稿频道成功");
        }else{
            return Result.error("新增投稿频道失败", "新增投稿频道失败");
        }
    }

    public int saveContributeChannel(ContributeChannel contributeChannel){
        return contributeChannelMapper.insertSelective(contributeChannel);
    }

    public List<ContributeChannel> listContributeChannel(){
        return contributeChannelMapper.listContributeChannel();
    }

    public int getContributeChannelCount(){
        return contributeChannelMapper.getContributeChannelCount();
    }

    public int updateContributeChannel(ContributeChannel contributeChannel){
        contributeChannel.setUpdateTime(new Date(System.currentTimeMillis()));
        return contributeChannelMapper.updateContributeChannel(contributeChannel);
    }

    public Result updateContributeChannel(ContributeChannelParam param){
        ContributeChannel contributeChannel = new ContributeChannel();
        BeanUtil.copyProperties(param, contributeChannel);
        int result = this.updateContributeChannel(contributeChannel);
        if(result>0){
            return Result.success("更新投稿频道名称成功");
        }else{
            return Result.error("更新投稿频道名称失败", "更新投稿频道名称失败");
        }
    }

    public Result deleteContributeChannel(int id){
        int count = contributeMapper.getCountByChannelId(id);
        if(count>0){
            return Result.error("投稿频道已经使用，不能删除", "投稿频道已经使用，不能删除");
        }
        int result = contributeChannelMapper.deleteContributeChannel(id);
        if(result>0){
            return Result.success("删除投稿频道成功");
        }else{
            return Result.error("删除投稿频道失败", "删除投稿频道失败");
        }
    }

    public ContributeType selectContributeTypeByPrimaryKey(int id){
        return contributeTypeMapper.selectByPrimaryKey(id);
    }

    public Result saveContributeType(ContributeTypeParam param){
        int count = contributeTypeMapper.getContributeTypeCount();
        if(count>=4){
            return Result.error("稿件类型已经超过4个，不能再增加", "稿件类型已经超过4个，不能再增加");
        }
        ContributeType contributeType = new ContributeType();
        BeanUtil.copyProperties(param, contributeType);
        int result = 0;
        try{
            result = this.saveContributeType(contributeType);
        }catch(DataAccessException e){
            log.error(e.getMessage(), e);
            return Result.error("投稿类型名称不能重复", "投稿类型名称不能重复");
        }
        if(result>0){
            return Result.success("新增投稿类型成功");
        }else{
            return Result.error("新增投稿类型失败", "新增投稿类型失败");
        }
    }

    public int saveContributeType(ContributeType contributeType){
        return contributeTypeMapper.insertSelective(contributeType);
    }

    public List<ContributeType> listContributeType(){
        return contributeTypeMapper.listContributeType();
    }

    public int getContributeTypeCount(){
        return contributeTypeMapper.getContributeTypeCount();
    }

    public int updateContributeType(ContributeType contributeType){
        contributeType.setUpdateTime(new Date(System.currentTimeMillis()));
        return contributeTypeMapper.updateContributeType(contributeType);
    }

    public Result updateContributeType(ContributeTypeParam param){
        ContributeType contributeType = new ContributeType();
        BeanUtil.copyProperties(param, contributeType);
        int result = this.updateContributeType(contributeType);
        if(result>0){
            return Result.success("更新投稿类型成功");
        }else{
            return Result.error("更新投稿类型失败", "更新投稿类型失败");
        }
    }

    public Result deleteContributeType(int id){
        int count = contributeMapper.getCountByType(id);
        if(count>0){
            return Result.error("投稿类型已经使用，不能删除", "投稿类型已经使用，不能删除");
        }
        int result = contributeTypeMapper.deleteContributeType(id);
        if(result>0){
            return Result.success("删除稿件类型成功");
        }else{
            return Result.error("删除稿件类型失败", "删除稿件类型失败");
        }
    }

    public Result queryContribute(ContributeQueryParam param){
        //先判断并查询Users表，因为users、user_inf表是在exam库
        List<String> userIdList = null;
        Set<String> hashSet = null;
        if(param.getContributeUser()!=null && param.getContributeUser().trim().length()>0){
            Users users = usersMapper.findUserByTel(param.getContributeUser());
            List<UserInfo> userInfoList = userInfoMapper.findUserInfoByNicknamePrecisMatch(param.getContributeUser());
            if(users!=null||(userInfoList!=null&&userInfoList.size()>0)){
                hashSet = new HashSet<String>();
                if(users!=null){
                    hashSet.add(users.getUserid());
                }
                if(userInfoList!=null && userInfoList.size()>0){
                    for(UserInfo userInfo:userInfoList){
                        hashSet.add(userInfo.getUserid());
                    }
                }
            }
            if(hashSet==null){
                List<Contribute> contributeList = new ArrayList<Contribute>();
                PageInfo<Contribute> contributePageInfo = new PageInfo<Contribute>(contributeList);
                return Result.success(contributePageInfo);
            }
        }
        if(hashSet!=null && !hashSet.isEmpty()){
            userIdList = new ArrayList<String>(hashSet);
            param.setUserIdList(userIdList);
        }

        Page<?> page = null;
        if(param.getPageNum()!=null && param.getPageSize() !=null){
            page = PageHelper.startPage(param.getPageNum(), param.getPageSize());
        }
        List<Contribute> contributeList = contributeMapper.queryContribute(param);
        PageInfo<Contribute> contributePageInfo = new PageInfo<Contribute>(contributeList);
        return Result.success(contributePageInfo);
    }

    public Result getContributeConfig(){
//        String contributeNotice = redisComponent.get(NewsConstant.CONTRIBUTE_NOTICE_KEY);
//        Integer maxCount = (Integer)redisObjectComponent.get(NewsConstant.CONTRIBUTE_ATTACHMENT_MAX_COUNT_KEY);
//        Integer maxSize = (Integer)redisObjectComponent.get(NewsConstant.CONTRIBUTE_ATTACHMENT_MAX_SIZE_KEY);
//        String attachmentNote = redisComponent.get(NewsConstant.CONTRIBUTE_ATTACHMENT_NOTE_KEY);
//        ContributeConfigParam param = new ContributeConfigParam();
//        param.setContributeNotice(contributeNotice);
//        param.setAttachmentMaxCount(maxCount);
//        param.setAttachmentMaxSize(maxSize);
//        param.setAttachmentNote(attachmentNote);
//        return Result.success(param);
        AttachmentConfig attachmentConfig = attachmentConfigMapper.selectByType(1);
        return Result.success(attachmentConfig);
    }

    public Result saveContributeConfig(AttachmentConfigParam param){
//        boolean f1 = redisComponent.set(NewsConstant.CONTRIBUTE_NOTICE_KEY, param.getContributeNotice());
//        boolean f2 = redisObjectComponent.set(NewsConstant.CONTRIBUTE_ATTACHMENT_MAX_COUNT_KEY, param.getAttachmentMaxCount());
//        boolean f3 = redisObjectComponent.set(NewsConstant.CONTRIBUTE_ATTACHMENT_MAX_SIZE_KEY, param.getAttachmentMaxSize());
//        boolean f4 = redisComponent.set(NewsConstant.CONTRIBUTE_ATTACHMENT_NOTE_KEY, param.getAttachmentNote());
//        if(f1&&f2&&f3&&f4){
//            return Result.success("保存稿件配置成功");
//        }else{
//            return Result.error("保存稿件配置失败", "保存稿件配置失败");
//        }
        AttachmentConfig attachmentConfig = new AttachmentConfig();
        BeanUtil.copyProperties(param, attachmentConfig);
        attachmentConfig.setUpdateTime(new Date(System.currentTimeMillis()));
        int result = attachmentConfigMapper.updateByPrimaryKeySelective(attachmentConfig);
        if(result>0){
            return Result.success("保存稿件配置成功");
        }else{
            return Result.error("保存稿件配置失败", "保存稿件配置失败");
        }
    }

    public Result processContribute(ContributeParam param, String processUserId){
        Contribute contribute = new Contribute();
        BeanUtil.copyProperties(param, contribute);
        contribute.setProcessUserId(processUserId);
        contribute.setProcessTime(new Date(System.currentTimeMillis()));

        int result = contributeMapper.updateContribute(contribute);
        if(result>0){
            return Result.success("处理投稿成功");
        }else{
            return Result.error("处理投稿失败", "处理投稿失败");
        }
    }

    public Result getContributeDetail(ContributeParam param){
        Contribute contribute = this.selectContributeByPrimaryKey(param.getId());
        String userId = contribute.getUserId();
        String processUserId = contribute.getProcessUserId();
        Users user = usersMapper.queryUserDetail(userId);//usersMapper.findUserByUserId(userId);
        UserBaseInfo userBaseInfo = userBaseInfoMapper.findUserBaseInfoByUserId(processUserId);
        List<ContributeAttachment> attachmentList = contributeAttachmentMapper.listByContributeId(param.getId());
        contribute.setUser(user);
        contribute.setUserBaseInfo(userBaseInfo);
        contribute.setAttachmentList(attachmentList);
        return Result.success(contribute);
    }

    public Result getContributeDetail(Integer id, Users user){
        Contribute contribute = this.selectContributeDetailByPrimaryKey(id);//this.selectContributeByPrimaryKey(id);
        String userId = user.getUserid();
        if(userId!=null && !userId.equals(contribute.getUserId())){
            return Result.error("您无权查看其它人的发布信息", "您无权查看其它人的发布信息");
        }
        List<ContributeAttachment> attachmentList = contributeAttachmentMapper.listByContributeId(id);
        contribute.setUser(user);
        contribute.setAttachmentList(attachmentList);
        return Result.success(contribute);
    }

    public int getCountByProcessStatus(int processStatus){
        int count = contributeMapper.getCountByProcessStatus(processStatus);
        return count;
    }

    public ContributePublishType selectContributePublishTypeByPrimaryKey(int id){
        return contributePublishTypeMapper.selectByPrimaryKey(id);
    }

    public int saveContributePublishType(ContributePublishType contributePublishType){
        return contributePublishTypeMapper.insertSelective(contributePublishType);
    }

    public Result saveContributePublishType(ContributePublishTypeParam param){
        int count = contributePublishTypeMapper.getContributePublishTypeCount();
        if(count>=16){
            return Result.error("发布类型已经达到16个，不能再增加", "发布类型已经达到16个，不能再增加");
        }
        ContributePublishType contributePublishType = new ContributePublishType();
        BeanUtil.copyProperties(param, contributePublishType);
        int result = 0;
        try{
            result = this.saveContributePublishType(contributePublishType);
        }catch(DataAccessException e){
            log.error(e.getMessage(), e);
            return Result.error("发布类型名称不能重复", "发布类型名称不能重复");
        }
        if(result>0){
            return Result.success("新增发布类型成功");
        }else{
            return Result.error("新增发布类型失败", "新增类型类型失败");
        }
    }

    public List<ContributePublishType> listContributePublishType(){
        return contributePublishTypeMapper.listContributePublishType();
    }

    public int getContributePublishTypeCount(){
        return contributePublishTypeMapper.getContributePublishTypeCount();
    }

    public int updateContributePublishType(ContributePublishType contributePublishType){
        return contributePublishTypeMapper.updateContributePublishType(contributePublishType);
    }

    public Result updateContributePublishType(ContributePublishTypeParam param){
        ContributePublishType contributePublishType = new ContributePublishType();
        BeanUtil.copyProperties(param, contributePublishType);
        int result = this.updateContributePublishType(contributePublishType);
        if(result>0){
            return Result.success("更新发布类型成功");
        }else{
            return Result.error("更新发布类型失败", "更新发布类型失败");
        }
    }

    public Result deleteContributePublishType(int id){
        int count = contributeMapper.getCountByPublishType(id);
        if(count>0){
            return Result.error("发布类型已经使用，不能删除", "发布类型已经使用，不能删除");
        }
        int result = contributePublishTypeMapper.deleteContributePublishType(id);
        if(result>0){
            return Result.success("删除发布类型成功");
        }else{
            return Result.error("删除发布类型失败", "删除发布类型失败");
        }
    }

    public Result listMyContribute(ContributeQueryParam param, String userId){
        Page<?> page = null;
        if(param.getPageNum()!=null && param.getPageSize() !=null){
            page = PageHelper.startPage(param.getPageNum(), param.getPageSize());
        }
        List<Contribute> contributeList = contributeMapper.queryContributeByUserId(userId);
        PageInfo<Contribute> contributePageInfo = new PageInfo<Contribute>(contributeList);
        return Result.success(contributePageInfo);
    }
}
